package CustomResources;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import EstructurasDeDatos.Arbol;
import Main.Aplicacion;

public class PanelArbol extends JPanel {

	private static final long serialVersionUID = 8000600396973330845L;
	private Arbol arbol;
	private Aplicacion padre;
	private int xMouse, yMouse;		//Se guarda la posición del mouse cuando sea necesario
	private int separacionH = 50;
	private int separacionV = 50;
	private JPopupMenu popupMenu;
	private JMenuItem itemMenuInsertarNodo = new JMenuItem("Agregar hijo");
	private JMenuItem itemMenuCrearArbol = new JMenuItem("Insertar raiz");
	private JMenuItem itemMenuMarcarComoVacio = new JMenuItem("Marcar como vacío");
	private JMenuItem itemMenuDesmarcarComoVacio = new JMenuItem("Desmarcar como vacío");
	private JMenuItem itemMenuEliminarNodo = new JMenuItem("Eliminar nodo");
	private JMenuItem itemMenuEliminarArbol = new JMenuItem("Eliminar subárbol");	
	
	public PanelArbol(Arbol arb,Aplicacion parent){
		padre = parent;
		arbol = arb;
		setBackground(Color.WHITE);
		
		//Se crea el menu que se desplegará cuando se haga click en un nodo
		popupMenu = new JPopupMenu();
			
		//Se agregan los listeners para los menu items
		itemMenuInsertarNodo.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				Arbol arbNew = new Arbol(obtenerSiguienteNombre());
				Arbol arbClicked = arbol.getSubArbol(arbol.getNodoClickeado(xMouse,yMouse).getId());
				arbClicked.agregarHijo(arbNew);
				repaint();
				padre.repaint();
			}
		});
					
		itemMenuCrearArbol.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				arbol = new Arbol(obtenerSiguienteNombre());
				padre.setArbol(arbol);
				repaint();
				padre.repaint();
			}
		});
		
		itemMenuMarcarComoVacio.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				Arbol arbClicked = arbol.getSubArbol(arbol.getNodoClickeado(xMouse,yMouse).getId());
				arbClicked.marcar();
				repaint();
				padre.repaint();
			}
		});
		
		itemMenuDesmarcarComoVacio.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				Arbol arbClicked = arbol.getSubArbol(arbol.getNodoClickeado(xMouse,yMouse).getId());
				arbClicked.desmarcar();
				repaint();
				padre.repaint();
			}
		});
		
		itemMenuEliminarNodo.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				Arbol arbolEliminado = arbol.removeSubArbol(arbol.getNodoClickeado(xMouse,yMouse));
				arbol.desmarcarHijosUnicos();
				if(arbolEliminado.equals(arbol)){
					arbol = null;
					padre.borrarArbol();
				}
				repaint();
				padre.repaint();
			}
		});
		
		itemMenuEliminarArbol.addActionListener(new ActionListener() {		
			public void actionPerformed(ActionEvent e) {
				Arbol arbolEliminado = arbol.removeSubArbol(arbol.getNodoClickeado(xMouse,yMouse));
				arbol.desmarcarHijosUnicos();
				if(arbolEliminado.equals(arbol)){
					arbol = null;
					padre.borrarArbol();
				}
				repaint();
				padre.repaint();
			}
		});
		
		this.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				int x=e.getX(),y=e.getY();
				if(SwingUtilities.isRightMouseButton(e) && e.getClickCount()==1 && estaDentroDeNodo(x,y)){
					//Si se clickeo un nodo del arbol, entonces hay que mostrar el popup correspondiente.
					//X e Y se guardan para saber cual es el nodo que se clickeo
					xMouse = x;
					yMouse = y;
					armarPopupMenu("Nodo",arbol.esHoja(arbol.getNodoClickeado(x,y).getId()),arbol.getNodoClickeado(x,y).getMarcado(),!arbol.esHijoHojaUnico(arbol.getNodoClickeado(x,y)));
					popupMenu.show(e.getComponent(),x,y);
				}
				else if(SwingUtilities.isRightMouseButton(e) && e.getClickCount()==1){
					//Si no se habia clickeado un nodo, sino el lienzo, comprobamos si hay algun arbol cargado
					//En caso que no lo haya, se muestra el menu para crearlo
					if(arbol == null){
						armarPopupMenu("Lienzo",null,null,null);
						popupMenu.show(e.getComponent(),x,y);
					}
				}
			}
		});
		
	}
	
	@Override
	public void paint(Graphics g){
		super.paint(g);
		int anchoCirc = 25;
		int altoCirc = 25;
		
		try{
			setearPosicionesNodos();
			//Obtenemos la raiz del grafo
			Arbol arbolRaiz = arbol.getRaiz();
			
			//Recorremos el grafo generando el Arbol
			List<Arbol> arbVisitados=new ArrayList<Arbol>();
			Deque<Arbol> arbPorVisitar=new ArrayDeque<Arbol>();
			Deque<Arbol> arbPadrePorVisitar=new ArrayDeque<Arbol>();
			arbPorVisitar.addFirst(arbolRaiz);
			arbPadrePorVisitar.addFirst(new Arbol("RAIZ"));
			while(!arbPorVisitar.isEmpty()){
				Arbol actual=arbPorVisitar.removeFirst();
				Arbol parent=arbPadrePorVisitar.removeFirst();
				if(arbVisitados.contains(actual))
					continue;
				else{
					arbVisitados.add(actual);
					//Dibujo el enlace al padre y el nodo del padre
					if(parent.getId()!="RAIZ" && !actual.getMarcado()){
						g.drawLine(actual.getX()+anchoCirc/2,actual.getY()+altoCirc/2,parent.getX()+anchoCirc/2,parent.getY()+altoCirc/2);
						g.fillOval(parent.getX(),parent.getY(),anchoCirc,altoCirc);
						g.setColor(Color.WHITE);
						g.setFont(new Font("Calibri",Font.BOLD, 12));
						g.drawString(parent.getId(),parent.getX()+(25/2-parent.getId().length()*3),parent.getY()+25/2+5);
						g.setColor(Color.BLACK);
					}
					else if(parent.getId()!="RAIZ"){
						g.setColor(new Color(239,228,176));
						g.drawLine(actual.getX()+anchoCirc/2,actual.getY()+altoCirc/2,parent.getX()+anchoCirc/2,parent.getY()+altoCirc/2);
						g.setColor(Color.BLACK);
						g.fillOval(parent.getX(),parent.getY(),anchoCirc,altoCirc);
						g.setColor(Color.WHITE);
						g.setFont(new Font("Calibri",Font.BOLD, 12));
						g.drawString(parent.getId(),parent.getX()+(25/2-parent.getId().length()*3),parent.getY()+25/2+5);
						g.setColor(Color.BLACK);
					}
					
					List<Arbol> sons = actual.getHijos();
					for(Arbol a : sons){
						if(!arbVisitados.contains(a)){
							arbPadrePorVisitar.addFirst(actual);
							arbPorVisitar.addFirst(arbol.getSubArbol(a.getId()));
						}
					}
					//Dibujo el nodo actual
					if(!actual.getMarcado()){
						g.fillOval(actual.getX(),actual.getY(),anchoCirc,altoCirc);
						g.setColor(Color.WHITE);
						g.setFont(new Font("Calibri",Font.BOLD, 12));
						g.drawString(actual.getId(),actual.getX()+(25/2-actual.getId().length()*3),actual.getY()+25/2+5);
						g.setColor(Color.BLACK);
						g.setFont(new Font("Calibri",Font.PLAIN, 10));
					}
					else{
						g.setColor(new Color(239,228,176));
						g.fillOval(actual.getX(),actual.getY(),anchoCirc,altoCirc);
						g.setColor(Color.WHITE);
						g.setFont(new Font("Calibri",Font.BOLD, 15));
						g.drawString(" λ",actual.getX()+(25/2-actual.getId().length()*3),actual.getY()+25/2+5);
						g.setColor(Color.BLACK);
						g.setFont(new Font("Calibri",Font.PLAIN, 10));
					}
				}
			}
		}catch(NullPointerException e){
			//Si no hay nodos, no debe graficar nada
		}
		try{
			g.setFont(new Font("Calibri",Font.BOLD,14));
			String[] rutaArchivo=padre.getRutaArchivoDatos().split("Files");
			String nombreFile=rutaArchivo[rutaArchivo.length-1];
			g.drawString(nombreFile.substring(1,nombreFile.length()),10,getHeight()-10);
		}catch(NullPointerException e){
			g.drawString("Arbol no guardado",10,getHeight()-10);
		}
	}
	
	private String obtenerSiguienteNombre(){
		String name=null;
		try{
		List<String> nombresNodos=arbol.getNombresNodos();
		int i=0,j=0;
		boolean estaRepetido=true;
		for(i=0;i<26 && estaRepetido;i++)
			for(j=0;j<10 && estaRepetido;j++){
				estaRepetido=false;
				name=Character.toString((char)(65+i))+Character.toString((char)(48+j));
				for(String s : nombresNodos)
					if(s.toLowerCase().equals(name.toLowerCase()))
						estaRepetido=true;
			}
		}catch(NullPointerException e){
			name = "A0";
		}
		return name;
	}

	private boolean estaDentroDeNodo(int x,int y){
		boolean estaDentro;
		try{
			estaDentro = arbol.estaDentroNodo(x,y);
		}catch(NullPointerException e){
			estaDentro = false;
		}
		return estaDentro;
	}
	
	private void setearPosicionesNodos(){
		arbol.setearPosiciones(1,separacionH,1,separacionV);
		setScale(1); //Para que se actualicen los scroll del scrollpane
	}

	public void setScale(int value) {
		int numHojas = arbol.obtenerCantidadHojas();
		int profundidad = arbol.obtenerProfundidadMaxima();
		setPreferredSize(new Dimension(numHojas*separacionH+100,profundidad*separacionV+100));  
	    revalidate();
	}
	
	private void armarPopupMenu(String tipoClick,Boolean esHoja,Boolean esVacio,Boolean poseeHermanosHoja){
		//Se crea el menu que se desplegará con el click
		popupMenu.removeAll();
		switch(tipoClick){
		case "Lienzo":
			popupMenu.add(itemMenuCrearArbol);
			break;
		case "Nodo":
			if(!esVacio)
				popupMenu.add(itemMenuInsertarNodo);
			if(esHoja)
				popupMenu.add(itemMenuEliminarNodo);
			else
				popupMenu.add(itemMenuEliminarArbol);
			if(esHoja && !esVacio && poseeHermanosHoja)
				popupMenu.add(itemMenuMarcarComoVacio);
			else if(esHoja && esVacio)
				popupMenu.add(itemMenuDesmarcarComoVacio);
			break;
		}
	}
	
}
